package transaction

import (
	"context"
	"crypto/ecdsa"
	"fmt"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/core/types"
	"github.com/ethereum/go-ethereum/crypto"
	"github.com/ethereum/go-ethereum/ethclient"
	"log"
	"math/big"
)
// https://goethereumbook.org/zh/transfer-eth/
var client * ethclient.Client

func init() {
	var err error
	client, err = ethclient.Dial("HTTP://127.0.0.1:8545")
	if err != nil {
		log.Fatalf("init: %v\n", err.Error())
	}
}
func check(err error)  {
	if err != nil {
		fmt.Printf("err: %v\n", err)
	}
}
func HeadByNumer()  {
	header, err := client.HeaderByNumber(context.Background(), nil)
	check(err)
	fmt.Printf("%v\n", header.Number.String())
}
func BlockByNumber()  {
	blockNumber := big.NewInt(0)
	block, err := client.BlockByNumber(context.Background(), blockNumber)
	check(err)
	fmt.Printf("block.Number().Uint64(): %v\n", block.Number().Uint64())
	fmt.Printf("block.Time():%v\n", block.Time())
	fmt.Printf("block.Difficulty().Uint64():%v\n", block.Difficulty().Uint64())
	fmt.Printf("block.Hash().Hex(): %v\n", block.Hash().Hex())
	fmt.Printf("transactions: %v\n", len(block.Transactions()))
	count, err := client.TransactionCount(context.Background(), block.Hash())
	check(err)
	fmt.Printf("count: %v\n", count)
}
func Transactions()  {
	blockNumber := big.NewInt(0)
	block, err := client.BlockByNumber(context.Background(), blockNumber)
	check(err)
	for i, transaction := range block.Transactions() {
		fmt.Printf("%v %v\n", i, transaction.Hash().Hex())
		fmt.Printf("%v %v\n", i, transaction.Value().String())
		fmt.Printf("%v %v\n", i, transaction.Gas())
		fmt.Printf("%v %v\n", i, transaction.GasPrice().Uint64())
		fmt.Printf("%v %v\n", i, transaction.Nonce())
		fmt.Printf("%v %v\n", i, transaction.Data())
		fmt.Printf("%v %v\n", i, transaction.To().Hex())

		chainId, err := client.NetworkID(context.Background())
		check(err)
		//types.NewEIP155Signer(chainId)
		//if msg, err := transaction.AsMessage(types.NewEIP155Signer(chainId)); err == nil {
		b := new(big.Int)
		b.SetString("1000", 16)
		if msg, err := transaction.AsMessage(types.NewEIP155Signer(chainId), b); err != nil {
			fmt.Printf("msg: %\vn", msg.From().Hex())
		}
		receipt, err := client.TransactionReceipt(context.Background(), transaction.Hash())
		check(err)
		fmt.Printf("recept: %v\n", receipt.Status)
		fmt.Printf("logs: %v\n", receipt.Logs)
	}
}
func TransactionInBlock()  {
	blockHash := common.HexToHash("")
	count, err := client.TransactionCount(context.Background(), blockHash)
	check(err)
	for idx := uint(0); idx < count; idx++ {
		tx, err := client.TransactionInBlock(context.Background(), blockHash, idx)
		check(err)
		fmt.Printf("%v\n", tx.Hash().Hex())
	}
}
func TransactionByHash()  {
	txHash := common.HexToHash("0x5d49fcaa394c97ec8a9c3e7bd9e8388d420fb050a52083ca52ff24b3b65bc9c2")
	tx, isPenging, err := client.TransactionByHash(context.Background(), txHash)
	check(err)
	fmt.Printf("hash hex: %v\n", tx.Hash().Hex())
	fmt.Printf("isPenging: %v\n", isPenging)
}
func HextoESCSA()  {
	privateKey, err := crypto.HexToECDSA("274018b7d63e62faeee46f97079fbe7cd73bc3ae20a784f9001d5962433dc3cf")
	check(err)
	publicKey := privateKey.Public()
	publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey)
	if !ok {
		log.Fatalf("%v\n", "cannot assert type: publickey is not of *ecdsa.PublicKey")
	}
	fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)
	nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
	check(err)
	value := big.NewInt(1000000000000000000) // 10ETH
	gasLimit := uint64(21000)
	//gasPrice := big.NewInt(30000000000)
	gasPrice, err := client.SuggestGasPrice(context.Background())
	check(err)
	toAddress := common.HexToAddress("0xb223F0D60e1ea25826A253E4d9914b3fA9141B9D")
	tx := types.NewTransaction(nonce, toAddress, value, gasLimit, gasPrice, nil)
	chainId, err := client.NetworkID(context.Background())
	check(err)
	signTx, err := types.SignTx(tx, types.NewEIP155Signer(chainId), privateKey)
	check(err)
	err = client.SendTransaction(context.Background(), signTx)
	check(err)
	fmt.Printf("tx send: %s\n", signTx.Hash().Hex())

	//types.NewTransactionsByPriceAndNonce()
	//types.NewTx()


}